/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package utils;

import com.sun.codemodel.JCodeModel;
import com.sun.tools.xjc.api.ErrorListener;
import com.sun.tools.xjc.api.S2JJAXBModel;
import com.sun.tools.xjc.api.SchemaCompiler;
import com.sun.tools.xjc.api.XJC;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Node;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

/**
 *
 * @author Hoang
 */
public class XMLUtils {

    public static Document parseDom(String fileXMLPath) throws ParserConfigurationException, SAXException, IOException {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.parse(fileXMLPath);
        return doc;

    }

    public static void writeDOMtoXML(String fileXMLPath, Node node) {
        try {
            TransformerFactory tff = TransformerFactory.newInstance();
            Transformer trans = tff.newTransformer();

            trans.setOutputProperty(OutputKeys.INDENT, "yes");

            Source src = new DOMSource(node);
            Result result = new StreamResult(new FileOutputStream(fileXMLPath));
            trans.transform(src, result);

        } catch (TransformerException ex) {
            Logger.getLogger(XMLUtils.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(XMLUtils.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static void doTransform(String xmlFile, String xslFile, String outputFile) {
        try {
            TransformerFactory tf = TransformerFactory.newInstance();
            StreamSource xslStream = new StreamSource(xslFile);
            Templates template = tf.newTemplates(xslStream);
            Transformer trans = template.newTransformer();

            Source xmlStream = new StreamSource(xmlFile);
            Result outputStream = new StreamResult(new FileOutputStream(outputFile));

            trans.transform(xmlStream, outputStream);
            System.out.println(outputFile + " created");
        } catch (TransformerException ex) {
            Logger.getLogger(XMLUtils.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(XMLUtils.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    //Parsing xml, cho phep truyen them parameter
    public static void doTransform(String xmlFile, String xslFile,
            String outputFile, Map<String, String> params) {
        try {
            TransformerFactory tf = TransformerFactory.newInstance();
            StreamSource xslStream = new StreamSource(xslFile);
            Templates template = tf.newTemplates(xslStream);
            Transformer trans = template.newTransformer();
            for (String key : params.keySet()) {
                String paramName = key;
                String paramValue = params.get(key);
                trans.setParameter(paramName, paramValue);
            }

            Source xmlStream = new StreamSource(xmlFile);
            Result outputStream = new StreamResult(new FileOutputStream(outputFile));

            trans.transform(xmlStream, outputStream);
            System.out.println(outputFile + "created");
        } catch (TransformerException ex) {
            Logger.getLogger(XMLUtils.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(XMLUtils.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /*
     * Sample use:
     * Customer item = (Customer) getObjectFromXML("src/customers.xml", new Customer());
     */
    public static Object getObjectFromXML(String XMLFilePatch, Class classesToBeBound) {
        try {
            JAXBContext jc = JAXBContext.newInstance(classesToBeBound);
            Unmarshaller u = jc.createUnmarshaller();
            File f = new File(XMLFilePatch);
            return u.unmarshal(f);
        } catch (JAXBException ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /*
     * Sample use:
     * writeObjectToXML("src/newFile.xml", item);
     */
    public static void writeObjectToXML(String XMLFilePath, Object object) {
        try {
            JAXBContext ctx = JAXBContext.newInstance(object.getClass());
            Marshaller mar = ctx.createMarshaller();
            mar.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
            mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            mar.marshal(object, new File(XMLFilePath));
        } catch (JAXBException ex) {
            ex.printStackTrace();
        }
    }

    public static void validateXML(String xmlFilePath, String schemaFilePath) throws SAXException {
        try {
            SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
            Schema schema = sf.newSchema(new File(schemaFilePath));
            Validator validator = schema.newValidator();
            validator.validate(new DOMSource(XMLUtils.parseDom(xmlFilePath)));
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(XMLUtils.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(XMLUtils.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /*Sample use
     * XMLUtils.generateJavaClass("src/xmlday11/customer.xsd", "src/", "sample.abcd");
     * Remeber the "src/" to generate in the source folder
     */
    public static void generateJavaClass(String xsdFilePath, String outputFolder, String packageName) {
        try {
            SchemaCompiler sc = XJC.createSchemaCompiler();
            sc.setErrorListener(new ErrorListener() {

                public void error(SAXParseException saxpe) {
                    System.out.println("Error: " + saxpe.getMessage());
                }

                public void fatalError(SAXParseException saxpe) {
                    System.out.println("Fatal: " + saxpe.getMessage());
                }

                public void warning(SAXParseException saxpe) {
                    System.out.println("Warning: " + saxpe.getMessage());
                }

                public void info(SAXParseException saxpe) {
                    System.out.println("Info: " + saxpe.getMessage());
                }
            });
            sc.forcePackageName(packageName);
            File schema = new File(xsdFilePath);
            InputSource is = new InputSource(schema.toURI().toString());
            sc.parseSchema(is);
            S2JJAXBModel model = sc.bind();
            JCodeModel code = model.generateCode(null, null);
            code.build(new File(outputFolder));
            System.out.println("Finished");
        } catch (IOException ex) {
            Logger.getLogger(XMLUtils.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
